package com.tanhua.sso.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tanhua.common.mapper.ManagerInfoMapper;
import com.tanhua.common.mapper.UserInfoMapper;
import com.tanhua.common.mapper.UserMapper;
import com.tanhua.common.pojo.User;
import com.tanhua.common.vo.ErrorResult;
import com.tanhua.dubbo.api.HuanXinApi;
import com.tanhua.dubbo.api.ManagerApi;
import com.tanhua.dubbo.mapper.FreezeMapper;
import com.tanhua.dubbo.pojo.Freeze;
import com.tanhua.sso.vo.UserVo;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.StringUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Don
 */
@Service
@Slf4j
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private FreezeMapper freezeMapper;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private ManagerInfoMapper managerInfoMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Reference
    private ManagerApi managerApi;

    @Value("${jwt.secret}")
    private String secret;

    @Reference
    private HuanXinApi huanXinApi;

    public ErrorResult login(String phone) {

        /**
         * 判断当前手机发送的验证码是否失效
         * 未失效 不再发送
         * 失效 发送验证码 将发送成功的验证码存入redis并设置失效时间
         */
        // 1.1 设计redis的key
        String redisKey = "CHECK_CODE_" + phone;

        // 1.2 判断是否失效
        Boolean flag = redisTemplate.hasKey(redisKey);

        //未失效 不再发送
        if (flag) {
            return ErrorResult.builder().errCode("000001").errMessage("验证码未失效!!!").build();
        }
        // 失效 发送验证码
        String code = "123456";
        // 将发送成功的验证码存入redis 并设置失效时间
        redisTemplate.opsForValue().set(redisKey, code, Duration.ofMinutes(5));

        return null;
    }


    public UserVo loginVerification(String phone, String code, String equipment) {
        // 根据 phone 获取redis中的key
        String redisKey = "CHECK_CODE_" + phone;
        // 从redis中获取验证码
        String redisCode = redisTemplate.opsForValue().get(redisKey);
        // 将输入的验证码与redis中的比较
        if (!StringUtils.equals(code, redisCode)) {
            // 不相同
            return null;
        }
        // 相同 校验手机号是否注册
        // 删除redis中的验证码
        redisTemplate.delete(redisKey);

        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getMobile, phone);
        // 查询数据库 返回user对象
        User user = userMapper.selectOne(wrapper);
        // 数据库不存在则未注册  新用户进行注册 isNew = true
        Boolean isNew = false;
        if (user == null) {
            user = new User();
            user.setMobile(phone);
            user.setPassword(DigestUtils.md5Hex("123456"));
            userMapper.insert(user);

            // 注册环信用户
            Boolean result = huanXinApi.register(user.getId());
            if (!result) {
                log.error("注册环信用户失败!!! userId =" + user.getId());
            }
            isNew = true;
        }
        // 老用户
        Map<String, Object> claims = new HashMap<String, Object>();
        claims.put("mobile", user.getMobile());
        claims.put("id", user.getId());

        // 判断是否冻结登录
        if (isFreeze(user.getId())) {
            return null;
        }


        // 生成token
        String token = Jwts.builder()
                .setClaims(claims) //payload，存放数据的位置，不能放置敏感数据，如：密码等
                .signWith(SignatureAlgorithm.HS256, secret) //设置加密方法和加密盐
                .setExpiration(new DateTime().plusHours(12).toDate()) //设置过期时间，12小时后过期
                .compact();

        //记录登录日志
        managerApi.saveLoginLog(user.getId(),equipment);

        return UserVo.builder().token(token).isNew(isNew).build();
    }


    public User queryUserByToken(String token) {
        try {
            // 通过token解析数据
            Map<String, Object> body = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();

            User user = new User();
            user.setId(Long.valueOf(body.get("id").toString()));
            user.setMobile(body.get("mobile").toString());

            //需要返回user对象中的mobile，需要查询数据库获取到mobile数据
            //如果每次都查询数据库，必然会导致性能问题，需要对用户的手机号进行缓存操作
            //数据缓存时，需要设置过期时间，过期时间要与token的时间一致
            //如果用户修改了手机号，需要同步修改redis中的数据

            return user;
        } catch (ExpiredJwtException e) {
            log.info("token已经过期！ token = " + token);
        } catch (Exception e) {
            log.error("token不合法！ token = " + token, e);
        }
        return null;
    }

    /**
     * 是否冻结登录
     *
     * @param userId
     * @return
     */
    private Boolean isFreeze(Long userId) {
        LambdaQueryWrapper<Freeze> query = new LambdaQueryWrapper<>();
        query.eq(Freeze::getUserId, userId);
        Freeze freeze = freezeMapper.selectOne(query);

        if (ObjectUtil.isEmpty(freeze)) {
            return false;
        }

        if (freeze.getFreezingRange() != 1) {
            return false;
        }

        if (freeze.getFreezingTime() == 1) {
            if (System.currentTimeMillis() - freeze.getCreated().getTime() > (3 * 24 * 60 * 60 * 1000)) {
                //冻结时间到期，用户解冻删除冻结表数据
                LambdaQueryWrapper<Freeze> queryFreeze = new LambdaQueryWrapper<>();
                queryFreeze.eq(Freeze::getUserId, userId);
                freezeMapper.delete(queryFreeze);
                return false;
            }
        }

        if (freeze.getFreezingTime() == 2) {
            if (System.currentTimeMillis() - freeze.getCreated().getTime() > (7 * 24 * 60 * 60 * 1000)) {
                //冻结时间到期，用户解冻删除冻结表数据
                LambdaQueryWrapper<Freeze> queryFreeze = new LambdaQueryWrapper<>();
                queryFreeze.eq(Freeze::getUserId, userId);
                freezeMapper.delete(queryFreeze);
                return false;
            }
        }

        return true;
    }


    /**
     * 更新用户手机号
     *
     * @param userId
     * @param newPhone
     */

    public Boolean updatePhoneNumber(Long userId, String newPhone) {
        // 去数据库查询手机号是否存在
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile",newPhone);
        User user = this.userMapper.selectOne(queryWrapper);

        if(ObjectUtil.isNotEmpty(user)){
            // 手机号已存在
            return false;
        }

        // 手机号不存在 重新封装信息
        user = new User();
        user.setId(userId);
        user.setMobile(newPhone);

        // 更新手机号
        return this.userMapper.updateById(user) > 0;
    }
}

